package lion.workflow;

import java.util.ArrayList;
import java.util.List;

import lion.dev.lang.MapJ;
import lion.dev.lang.XMLUtil;
import lion.workflow.handler.WorkflowHandlers;
import lion.workflow.model.WorkFlowModel;

import org.apache.commons.lang.StringUtils;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.DocumentHelper;
import org.dom4j.Element;

/**
 * @author lion
 * @email hl_0074@sina.com
 * @date 2014年7月24日
 */
public class WorkFlow {

	private WorkFlowModel workFlowModel;

	public WorkFlow(WorkFlowModel wfm) {

		this.workFlowModel = wfm;
	}

	protected IWorkflowHandler handler;
	protected List<WorkFlowState> states;

	public List<WorkFlowState> getStates() {

		if (this.states == null) {
			init();
		}

		return this.states;
	}

	public void init() {

		Document doc = null;
		try {
			doc = DocumentHelper.parseText(this.workFlowModel.getXml());
		} catch (DocumentException e) {
			throw new WorkFlowException("parse workflow xml config failed:", e);
		}

		// init handler
		this.handler = WorkflowHandlers.getHandler(this.workFlowModel.getType());

		this.states = new ArrayList<>();
		List<Element> nodes = doc.selectNodes("/workflow/state");
		for (Element el : nodes) {
			WorkFlowState wfs = new WorkFlowState(XMLUtil.attributeMap(el));
			for (Element sub : (List<Element>) el.selectNodes("transition")) {

				List<Element> conEles = sub.selectNodes("condition");
				List<MapJ> conditions = new ArrayList<>();
				for (Element c : conEles) {
					conditions.add(XMLUtil.attributeMap(c));
				}
				WorkFlowTransition wft = new WorkFlowTransition(XMLUtil.attributeMap(sub), conditions);
				wfs.addTransition(wft);
			}
			this.states.add(wfs);
		}
	}

	public IWorkflowHandler getHandler() {

		if (this.handler == null) {
			init();
		}
		return this.handler;
	}

	public WorkFlowState getStartState() {

		for (WorkFlowState wfs : getStates()) {
			if (wfs.isStart()) { return wfs; }
		}

		throw new WorkFlowException("workflow start state not found : ");
	}

	public WorkFlowState getEndState() {

		for (WorkFlowState wfs : getStates()) {
			if (wfs.isEnd()) { return wfs; }
		}

		throw new WorkFlowException("workflow end state not found  ");
	}

	public WorkFlowState getState(String name) {

		for (WorkFlowState state : getStates()) {
			if (StringUtils.equals(state.getName(), name)) { return state; }
		}

		return null;
	}

	public boolean isEndState(String stateName) {

		WorkFlowState state = getState(stateName);
		if (state == null) { return false; }

		return state.isEnd();
	}

	public boolean isStartState(String stateName) {

		WorkFlowState state = getState(stateName);
		if (state == null) { return false; }

		return state.isStart();
	}
}
